//
//  ConnectorLayoutViewController.m
//  CocoaSynth
//
//  Created by Thomas Dupont on 19/02/10.
//  Copyright 2010 Apple Inc. All rights reserved.
//

#import "ConnectorLayoutViewController.h"

#import "ModuleViewController.h"
#import "PortInViewController.h"
#import "PortOutViewController.h"
#import "ConnectorViewController.h"
#import "ConnectorLayoutView.h"
#import "ModuleConnectors.h"

@implementation ConnectorLayoutViewController

- (id)init
{
	if (self = [super init]) {
		ConnectorLayoutView* layoutView = [[ConnectorLayoutView alloc] initWithFrame:NSMakeRect(0, 0, 745, 335)];
		self.view = layoutView;
		
		portsByModule = [[NSMutableDictionary alloc] init];
		connectors = [[NSMutableSet alloc] init];
		selectedPortIn = nil;
		selectedPortOut = nil;
	}
	return self;
}

#pragma mark -
#pragma mark Connector creation

- (void)createConnectorWithPortIn:(PortInViewController*)aPortIn andPortOut:(PortOutViewController*)aPortOut
{
	ModuleViewController* portInModule = [aPortIn module];
	ModuleViewController* portOutModule = [aPortOut module];
	
	ModuleConnectors* portInSet = [portsByModule objectForKey:[portInModule name]];
	
	if (portInSet == nil) {
		ModuleConnectors* moduleConnectors = [[ModuleConnectors alloc] initWithName:[portInModule name]];
		[moduleConnectors addPort:aPortIn];
		
		[portsByModule setObject:moduleConnectors forKey:[portInModule name]];
		[moduleConnectors release];
	} else {
		[portInSet addPort:aPortIn];
	}
	
	ModuleConnectors* portOutSet = [portsByModule objectForKey:[portOutModule name]];
	
	if (portOutSet == nil) {
		ModuleConnectors* moduleConnectors = [[ModuleConnectors alloc] initWithName:[portOutModule name]];
		[moduleConnectors addPort:aPortOut];
		
		[portsByModule setObject:moduleConnectors forKey:[portOutModule name]];
		[moduleConnectors release];
	} else {
		[portOutSet addPort:aPortOut];
	}
	
	ConnectorViewController* connector = [[ConnectorViewController alloc] initWithLayout:self andPortIn:aPortIn andPortOut:aPortOut];
	
	[self.view addSubview:connector.view];
	[connectors addObject:connector];
	[connector release];
}

#pragma mark -
#pragma mark Ports selection

- (void)selectPortIn:(PortInViewController*)aPort
{
	//if the port is already connected...
	if ([(ModuleConnectors*)[portsByModule objectForKey:[[aPort module] name]] containsPort:aPort]) {
		selectedPortOut = nil;
		[(ConnectorLayoutView*)self.view clearConnector];
	}
	else {
		if (selectedPortOut == nil) {
			selectedPortIn = aPort;
			[(ConnectorLayoutView*)self.view drawTemporaryConnectorFrom:aPort];
		} else {
			[self createConnectorWithPortIn:aPort andPortOut:selectedPortOut];
			selectedPortOut = nil;
			[(ConnectorLayoutView*)self.view clearConnector];
		}
	}
}

- (void)selectPortOut:(PortOutViewController*)aPort
{
	//if the port is already connected...
	if ([(ModuleConnectors*)[portsByModule objectForKey:[[aPort module] name]] containsPort:aPort]) {
		selectedPortIn = nil;
		[(ConnectorLayoutView*)self.view clearConnector];
	}
	else {
		if (selectedPortIn == nil) {
			selectedPortOut = aPort;
			[(ConnectorLayoutView*)self.view drawTemporaryConnectorFrom:aPort];
		} else {
			[self createConnectorWithPortIn:selectedPortIn andPortOut:aPort];
			selectedPortIn = nil;
			[(ConnectorLayoutView*)self.view clearConnector];
		}
		
	}
}

- (void)unselectPorts
{
	selectedPortIn = nil;
	selectedPortOut = nil;
	[(ConnectorLayoutView*)self.view clearConnector];
}

- (void)disconnectPort:(PortViewController*)aPort
{
	if ([(ModuleConnectors*)[portsByModule objectForKey:[[aPort module] name]] containsPort:aPort]) {
		NSEnumerator* connectorEnum = [connectors objectEnumerator];
		ConnectorViewController* currentConnector;
		NSMutableSet* connectorsToRemove = [[NSMutableSet alloc] init];
		NSMutableSet* portsToRemove = [[NSMutableSet alloc] init];
		while (currentConnector = [connectorEnum nextObject]) {
			if ([currentConnector containsPort:aPort]) {
				[connectorsToRemove addObject:currentConnector];
				[portsToRemove addObject:[currentConnector portIn]];
				[portsToRemove addObject:[currentConnector portOut]];
				[[currentConnector view] removeFromSuperview];
			}
		}
		NSEnumerator* connectorsToRemoveEnum = [connectorsToRemove objectEnumerator];
		while (currentConnector = [connectorsToRemoveEnum nextObject]) {
			[currentConnector disconnect];
			[connectors removeObject:currentConnector];
		}
		NSEnumerator* portsToRemoveEnum = [portsToRemove objectEnumerator];
		PortViewController* currentPort;
		while (currentPort = [portsToRemoveEnum nextObject]) {
			[(ModuleConnectors*)[portsByModule objectForKey:[[currentPort module] name]] removePort:currentPort];
		}
		[portsToRemove release];
		[connectorsToRemove release];
	}
}

- (void)refresh
{
	for (ConnectorViewController* c in connectors)
	{
		[c refresh];
	}
}

@end
